#ifndef MESH_EXCEPTIONS_HPP
#define MESH_EXCEPTIONS_HPP

#include <string>
#include <exception>
#include <utility>

namespace hms
{

	
/* to get meaningful error messages, exception classes can define a type and
 * inherit from ErrorWithType, which concatenates the type and the passed in
 * error message for what() output */
class ErrorWithType: public std::exception
{
protected:
	std::string m_error;
	
	std::string errorMsg( const char* type, std::string error )
	{
		return std::string{type} + ": " + std::move(error);
	}
	
public:
	ErrorWithType( const char* type, std::string error ) :
		m_error { errorMsg( type, std::move(error) ) }
	{}
	
	const char* what() const noexcept override
	{
		return m_error.c_str();
	}
};
	


class InputError: public ErrorWithType
{
private:
	static constexpr auto m_type { "Input error" };

public:
	InputError( std::string error ) :
		ErrorWithType( m_type, std::move(error) )
	{}
};
	


class MeshError: public ErrorWithType
{
private:
	static constexpr auto m_type { "Mesh error" };

public:
	MeshError( std::string error ) :
		ErrorWithType( m_type, std::move(error) )
	{}
};



class FileError : public ErrorWithType
{
private:
	static constexpr auto m_type { "File error" };

public:
	FileError( std::string error ) :
		ErrorWithType( m_type, std::move(error) )
	{}
};



class IOStreamError: public ErrorWithType
{
private:
	static constexpr auto m_type { "I/O stream error" };

public:
	IOStreamError( std::string error ) :
		ErrorWithType( m_type, std::move(error) )
	{}
};



class ParseError: public ErrorWithType
{
private:
	static constexpr auto m_type { "Parse error" };

public:
	ParseError( const std::string& error ) :
		ErrorWithType( m_type, error )
	{}
};



class FunctionParserError: public ErrorWithType
{
private:
	static constexpr auto m_type { "Function parser error" };

public:
	FunctionParserError( std::string error ) :
		ErrorWithType( m_type, std::move(error) )
	{}
};



class BoundaryConditionError : public ErrorWithType
{
private:
	static constexpr auto m_type { "Boundary Condition error" };

public:
	BoundaryConditionError( std::string error ) :
		ErrorWithType( m_type, std::move(error) )
	{}
};


/* prints warnings to std::cerr */
void warning( std::string message );



}

#endif